home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: zbfont.c,v 1.6 2000/09/19 19:00:52 lpd Exp $ */
- /* Font creation utilities */
- #include "memory_.h"
- #include "string_.h"
- #include "ghost.h"
- #include "oper.h"
- #include "gxfixed.h"
- #include "gsmatrix.h"
- #include "gxdevice.h"
- #include "gxfont.h"
- #include "bfont.h"
- #include "ialloc.h"
- #include "idict.h"
- #include "idparam.h"
- #include "ilevel.h"
- #include "iname.h"
- #include "interp.h" /* for initial_enter_name */
- #include "ipacked.h"
- #include "istruct.h"
- #include "store.h"
-
- /* Registered encodings. See ifont.h for documentation. */
- ref registered_Encodings;
- private ref *const registered_Encodings_p = ®istered_Encodings;
-
- /* Structure descriptor */
- public_st_font_data();
-
- /* Initialize the font building operators */
- private int
- zbfont_init(i_ctx_t *i_ctx_p)
- {
- /* Initialize the registered Encodings. */
- int i;
-
- ialloc_ref_array(®istered_Encodings, a_all,
- registered_Encodings_countof,
- "registered_Encodings");
- for (i = 0; i < registered_Encodings_countof; i++)
- make_empty_array(®istered_Encoding(i), 0);
- initial_enter_name("registeredencodings", ®istered_Encodings);
- return gs_register_ref_root(imemory, NULL,
- (void **)®istered_Encodings_p,
- "registered_Encodings");
- }
-
- /* <string|name> <font_dict> .buildfont3 <string|name> <font> */
- /* Build a type 3 (user-defined) font. */
- private int
- zbuildfont3(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- int code;
- build_proc_refs build;
- gs_font_base *pfont;
-
- check_type(*op, t_dictionary);
- code = build_gs_font_procs(op, &build);
- if (code < 0)
- return code;
- code = build_gs_simple_font(i_ctx_p, op, &pfont, ft_user_defined,
- &st_gs_font_base, &build, bf_options_none);
- if (code < 0)
- return code;
- return define_gs_font((gs_font *) pfont);
- }
-
- /* Encode a character. */
- gs_glyph
- zfont_encode_char(gs_font *pfont, gs_char chr, gs_glyph_space_t ignored)
- {
- const ref *pencoding = &pfont_data(pfont)->Encoding;
- ulong index = chr; /* work around VAX widening bug */
- ref cname;
- int code = array_get(pencoding, (long)index, &cname);
-
- if (code < 0 || !r_has_type(&cname, t_name))
- return gs_no_glyph;
- return (gs_glyph)name_index(&cname);
- }
-
- /* Encode a character in a known encoding. */
- private gs_glyph
- zfont_known_encode(gs_char chr, int encoding_index)
- {
- ulong index = chr; /* work around VAX widening bug */
- ref cname;
- int code;
-
- if (encoding_index < 0)
- return gs_no_glyph;
- code = array_get(®istered_Encoding(encoding_index),
- (long)index, &cname);
- if (code < 0 || !r_has_type(&cname, t_name))
- return gs_no_glyph;
- return (gs_glyph) name_index(&cname);
- }
-
- /* Get the name of a glyph. */
- /* The following typedef is needed to work around a bug in */
- /* some AIX C compilers. */
- typedef const char *const_chars;
- private const_chars
- zfont_glyph_name(gs_glyph index, uint * plen)
- {
- ref nref, sref;
-
- if (index >= gs_min_cid_glyph) { /* Fabricate a numeric name. */
- char cid_name[sizeof(gs_glyph) * 3 + 1];
- int code;
-
- sprintf(cid_name, "%lu", (ulong) index);
- code = name_ref((const byte *)cid_name, strlen(cid_name),
- &nref, 1);
- if (code < 0)
- return 0; /* What can we possibly do here? */
- } else
- name_index_ref(index, &nref);
- name_string_ref(&nref, &sref);
- *plen = r_size(&sref);
- return (const char *)sref.value.const_bytes;
- }
-
- /* ------ Initialization procedure ------ */
-
- const op_def zbfont_op_defs[] =
- {
- {"2.buildfont3", zbuildfont3},
- op_def_end(zbfont_init)
- };
-
- /* ------ Subroutines ------ */
-
- /* Convert strings to executable names for build_proc_refs. */
- int
- build_proc_name_refs(build_proc_refs * pbuild,
- const char *bcstr, const char *bgstr)
- {
- int code;
-
- if (!bcstr)
- make_null(&pbuild->BuildChar);
- else {
- if ((code = name_ref((const byte *)bcstr, strlen(bcstr), &pbuild->BuildChar, 0)) < 0)
- return code;
- r_set_attrs(&pbuild->BuildChar, a_executable);
- }
- if (!bgstr)
- make_null(&pbuild->BuildGlyph);
- else {
- if ((code = name_ref((const byte *)bgstr, strlen(bgstr), &pbuild->BuildGlyph, 0)) < 0)
- return code;
- r_set_attrs(&pbuild->BuildGlyph, a_executable);
- }
- return 0;
- }
-
- /* Get the BuildChar and/or BuildGlyph routines from a (base) font. */
- int
- build_gs_font_procs(os_ptr op, build_proc_refs * pbuild)
- {
- int ccode, gcode;
- ref *pBuildChar;
- ref *pBuildGlyph;
-
- check_type(*op, t_dictionary);
- ccode = dict_find_string(op, "BuildChar", &pBuildChar);
- gcode = dict_find_string(op, "BuildGlyph", &pBuildGlyph);
- if (ccode <= 0) {
- if (gcode <= 0)
- return_error(e_invalidfont);
- make_null(&pbuild->BuildChar);
- } else {
- check_proc(*pBuildChar);
- pbuild->BuildChar = *pBuildChar;
- }
- if (gcode <= 0)
- make_null(&pbuild->BuildGlyph);
- else {
- check_proc(*pBuildGlyph);
- pbuild->BuildGlyph = *pBuildGlyph;
- }
- return 0;
- }
-
- /* Do the common work for building a primitive font -- one whose execution */
- /* algorithm is implemented in C (Type 1, Type 2, Type 4, or Type 42). */
- /* The caller guarantees that *op is a dictionary. */
- int
- build_gs_primitive_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
- font_type ftype, gs_memory_type_ptr_t pstype,
- const build_proc_refs * pbuild,
- build_font_options_t options)
- {
- ref *pcharstrings = 0;
- ref CharStrings;
- gs_font_base *pfont;
- font_data *pdata;
- int code;
-
- if (dict_find_string(op, "CharStrings", &pcharstrings) <= 0) {
- if (!(options & bf_CharStrings_optional))
- return_error(e_invalidfont);
- } else {
- ref *ignore;
-
- if (!r_has_type(pcharstrings, t_dictionary))
- return_error(e_invalidfont);
- if ((options & bf_notdef_required) != 0 &&
- dict_find_string(pcharstrings, ".notdef", &ignore) <= 0
- )
- return_error(e_invalidfont);
- /*
- * Since build_gs_simple_font may resize the dictionary and cause
- * pointers to become invalid, save CharStrings.
- */
- CharStrings = *pcharstrings;
- }
- code = build_gs_outline_font(i_ctx_p, op, ppfont, ftype, pstype, pbuild,
- options, build_gs_simple_font);
- if (code != 0)
- return code;
- pfont = *ppfont;
- pdata = pfont_data(pfont);
- if (pcharstrings)
- ref_assign(&pdata->CharStrings, &CharStrings);
- else
- make_null(&pdata->CharStrings);
- /* Check that the UniqueIDs match. This is part of the */
- /* Adobe protection scheme, but we may as well emulate it. */
- if (uid_is_valid(&pfont->UID) &&
- !dict_check_uid_param(op, &pfont->UID)
- )
- uid_set_invalid(&pfont->UID);
- return 0;
- }
-
- /* Build a FDArray entry for a CIDFontType 0 font. */
- /* Note that as of Adobe PostScript version 3011, this may be either */
- /* a Type 1 or Type 2 font. */
- private int
- build_FDArray_sub_font(i_ctx_t *i_ctx_p, ref *op,
- gs_font_base **ppfont,
- font_type ftype, gs_memory_type_ptr_t pstype,
- const build_proc_refs * pbuild,
- build_font_options_t ignore_options)
- {
- gs_font *pfont;
- int code = build_gs_sub_font(i_ctx_p, op, &pfont, ftype, pstype, pbuild,
- NULL, op);
-
- if (code >= 0)
- *ppfont = (gs_font_base *)pfont;
- return code;
- }
- int
- build_gs_FDArray_font(i_ctx_t *i_ctx_p, ref *op,
- gs_font_base **ppfont,
- font_type ftype, gs_memory_type_ptr_t pstype,
- const build_proc_refs * pbuild)
- {
- gs_font_base *pfont;
- font_data *pdata;
- int code = build_gs_outline_font(i_ctx_p, op, &pfont, ftype, pstype,
- pbuild, bf_options_none,
- build_FDArray_sub_font);
- static const double bbox[4] = { 0, 0, 0, 0 };
- gs_uid uid;
-
- if (code < 0)
- return code;
- pdata = pfont_data(pfont);
- /* Fill in members normally set by build_gs_primitive_font. */
- make_null(&pdata->CharStrings);
- /* Fill in members normally set by build_gs_simple_font. */
- uid_set_invalid(&uid);
- init_gs_simple_font(pfont, bbox, &uid);
- pfont->encoding_index = ENCODING_INDEX_UNKNOWN;
- pfont->nearest_encoding_index = ENCODING_INDEX_UNKNOWN;
- /* Fill in members normally set by build_gs_font. */
- pfont->key_name = pfont->font_name;
- *ppfont = pfont;
- return 0;
- }
-
- /* Do the common work for building an outline font -- a non-composite font */
- /* for which PaintType and StrokeWidth are meaningful. */
- /* The caller guarantees that *op is a dictionary. */
- int
- build_gs_outline_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
- font_type ftype, gs_memory_type_ptr_t pstype,
- const build_proc_refs * pbuild,
- build_font_options_t options,
- build_base_font_proc_t build_base_font)
- {
- int painttype;
- float strokewidth;
- gs_font_base *pfont;
- int code = dict_int_param(op, "PaintType", 0, 3, 0, &painttype);
-
- if (code < 0)
- return code;
- code = dict_float_param(op, "StrokeWidth", 0.0, &strokewidth);
- if (code < 0)
- return code;
- code = build_base_font(i_ctx_p, op, ppfont, ftype, pstype, pbuild,
- options);
- if (code != 0)
- return code;
- pfont = *ppfont;
- pfont->PaintType = painttype;
- pfont->StrokeWidth = strokewidth;
- return 0;
- }
-
- /* Do the common work for building a font of any non-composite FontType. */
- /* The caller guarantees that *op is a dictionary. */
- int
- build_gs_simple_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
- font_type ftype, gs_memory_type_ptr_t pstype,
- const build_proc_refs * pbuild,
- build_font_options_t options)
- {
- double bbox[4];
- gs_uid uid;
- int code;
- gs_font_base *pfont;
-
- code = font_bbox_param(op, bbox);
- if (code < 0)
- return code;
- if ((options & bf_FontBBox_required) &&
- bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0
- )
- return_error(e_invalidfont);
- code = dict_uid_param(op, &uid, 0, imemory, i_ctx_p);
- if (code < 0)
- return code;
- if ((options & bf_UniqueID_ignored) && uid_is_UniqueID(&uid))
- uid_set_invalid(&uid);
- code = build_gs_font(i_ctx_p, op, (gs_font **) ppfont, ftype, pstype,
- pbuild, options);
- if (code != 0) /* invalid or scaled font */
- return code;
- pfont = *ppfont;
- pfont->procs.init_fstack = gs_default_init_fstack;
- pfont->procs.define_font = gs_no_define_font;
- pfont->procs.make_font = zbase_make_font;
- pfont->procs.next_char_glyph = gs_default_next_char_glyph;
- init_gs_simple_font(pfont, bbox, &uid);
- lookup_gs_simple_font_encoding(pfont);
- return 0;
- }
-
- /* Initialize the FontBBox and UID of a non-composite font. */
- void
- init_gs_simple_font(gs_font_base *pfont, const double bbox[4],
- const gs_uid *puid)
- {
- pfont->FontBBox.p.x = bbox[0];
- pfont->FontBBox.p.y = bbox[1];
- pfont->FontBBox.q.x = bbox[2];
- pfont->FontBBox.q.y = bbox[3];
- pfont->UID = *puid;
- }
-
- /* Compare the encoding of a simple font with the registered encodings. */
- void
- lookup_gs_simple_font_encoding(gs_font_base * pfont)
- {
- const ref *pfe = &pfont_data(pfont)->Encoding;
- int index;
-
- for (index = NUM_KNOWN_REAL_ENCODINGS; --index >= 0;)
- if (obj_eq(pfe, ®istered_Encoding(index)))
- break;
- pfont->encoding_index = index;
- if (index < 0) { /* Look for an encoding that's "close". */
- int near_index = -1;
- uint esize = r_size(pfe);
- uint best = esize / 3; /* must match at least this many */
-
- for (index = NUM_KNOWN_REAL_ENCODINGS; --index >= 0;) {
- const ref *pre = ®istered_Encoding(index);
- bool r_packed = r_has_type(pre, t_shortarray);
- bool f_packed = !r_has_type(pfe, t_array);
- uint match = esize;
- int i;
- ref fchar, rchar;
- const ref *pfchar = &fchar;
-
- if (r_size(pre) != esize)
- continue;
- for (i = esize; --i >= 0;) {
- uint rnidx;
-
- if (r_packed)
- rnidx = packed_name_index(pre->value.packed + i);
- else {
- array_get(pre, (long)i, &rchar);
- rnidx = name_index(&rchar);
- }
- if (f_packed)
- array_get(pfe, (long)i, &fchar);
- else
- pfchar = pfe->value.const_refs + i;
- if (!r_has_type(pfchar, t_name) ||
- name_index(pfchar) != rnidx
- )
- if (--match <= best)
- break;
- }
- if (match > best)
- best = match,
- near_index = index;
- }
- index = near_index;
- }
- pfont->nearest_encoding_index = index;
- }
-
- /* Get FontMatrix and FontName parameters. */
- private void get_font_name(P2(ref *, const ref *));
- private void copy_font_name(P2(gs_font_name *, const ref *));
- private int
- sub_font_params(const ref *op, gs_matrix *pmat, ref *pfname)
- {
- ref *pmatrix;
- ref *pfontname;
-
- if (dict_find_string(op, "FontMatrix", &pmatrix) <= 0 ||
- read_matrix(pmatrix, pmat) < 0
- )
- return_error(e_invalidfont);
- if (dict_find_string(op, "FontName", &pfontname) > 0)
- get_font_name(pfname, pfontname);
- else
- make_empty_string(pfname, a_readonly);
- return 0;
- }
-
- /* Do the common work for building a font of any FontType. */
- /* The caller guarantees that *op is a dictionary. */
- /* op[-1] must be the key under which the font is being registered */
- /* in FontDirectory, normally a name or string. */
- /* Return 0 for a new font, 1 for a font made by makefont or scalefont, */
- /* or a negative error code. */
- int
- build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype,
- gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild,
- build_font_options_t options)
- {
- ref kname; /* t_string */
- ref *pftype;
- ref *pencoding = 0;
- bool bitmapwidths;
- int exactsize, inbetweensize, transformedchar;
- int wmode;
- int code;
- gs_font *pfont;
- ref *pfid;
- ref *aop = dict_access_ref(op);
-
- get_font_name(&kname, op - 1);
- if (dict_find_string(op, "FontType", &pftype) <= 0 ||
- !r_has_type(pftype, t_integer) ||
- pftype->value.intval != (int)ftype
- )
- return_error(e_invalidfont);
- if (dict_find_string(op, "Encoding", &pencoding) <= 0) {
- if (!(options & bf_Encoding_optional))
- return_error(e_invalidfont);
- } else {
- if (!r_is_array(pencoding))
- return_error(e_invalidfont);
- }
- if ((code = dict_int_param(op, "WMode", 0, 1, 0, &wmode)) < 0 ||
- (code = dict_bool_param(op, "BitmapWidths", false, &bitmapwidths)) < 0 ||
- (code = dict_int_param(op, "ExactSize", 0, 2, fbit_use_bitmaps, &exactsize)) < 0 ||
- (code = dict_int_param(op, "InBetweenSize", 0, 2, fbit_use_outlines, &inbetweensize)) < 0 ||
- (code = dict_int_param(op, "TransformedChar", 0, 2, fbit_use_outlines, &transformedchar)) < 0
- )
- return code;
- code = dict_find_string(op, "FID", &pfid);
- if (code > 0) {
- if (!r_has_type(pfid, t_fontID))
- return_error(e_invalidfont);
- /*
- * If this font has a FID entry already, it might be
- * a scaled font made by makefont or scalefont;
- * in a Level 2 environment, it might be an existing font
- * being registered under a second name, or a re-encoded
- * font (which is questionable PostScript, but dvips
- * is known to do this).
- */
- pfont = r_ptr(pfid, gs_font);
- if (pfont->base == pfont) { /* original font */
- if (!level2_enabled)
- return_error(e_invalidfont);
- if (obj_eq(pfont_dict(pfont), op)) {
- *ppfont = pfont;
- return 1;
- }
- /*
- * This is a re-encoded font, or some other
- * questionable situation in which the FID
- * was preserved. Pretend the FID wasn't there.
- */
- } else { /* This was made by makefont or scalefont. */
- /* Just insert the new name. */
- gs_matrix mat;
- ref fname; /* t_string */
-
- code = sub_font_params(op, &mat, &fname);
- if (code < 0)
- return code;
- code = 1;
- copy_font_name(&pfont->font_name, &fname);
- goto set_name;
- }
- }
- /* This is a new font. */
- if (!r_has_attr(aop, a_write))
- return_error(e_invalidaccess);
- {
- ref encoding;
-
- /*
- * Since add_FID may resize the dictionary and cause
- * pencoding to become invalid, save the Encoding.
- */
- if (pencoding) {
- encoding = *pencoding;
- pencoding = &encoding;
- }
- code = build_gs_sub_font(i_ctx_p, op, &pfont, ftype, pstype,
- pbuild, pencoding, op);
- if (code < 0)
- return code;
- }
- pfont->BitmapWidths = bitmapwidths;
- pfont->ExactSize = (fbit_type)exactsize;
- pfont->InBetweenSize = (fbit_type)inbetweensize;
- pfont->TransformedChar = (fbit_type)transformedchar;
- pfont->WMode = wmode;
- code = 0;
- set_name:
- copy_font_name(&pfont->key_name, &kname);
- *ppfont = pfont;
- return code;
- }
-
- /* Create a sub-font -- a font or an entry in the FDArray of a CIDFontType 0 */
- /* font. Default BitmapWidths, ExactSize, InBetweenSize, TransformedChar, */
- /* and WMode; do not fill in key_name. */
- /* The caller guarantees that *op is a dictionary. */
- int
- build_gs_sub_font(i_ctx_t *i_ctx_p, const ref *op, gs_font **ppfont,
- font_type ftype, gs_memory_type_ptr_t pstype,
- const build_proc_refs * pbuild, const ref *pencoding,
- ref *fid_op)
- {
- gs_matrix mat;
- ref fname; /* t_string */
- gs_font *pfont;
- font_data *pdata;
- /*
- * Make sure that we allocate the font data
- * in the same VM as the font dictionary.
- */
- uint space = ialloc_space(idmemory);
- int code = sub_font_params(op, &mat, &fname);
-
- if (code < 0)
- return code;
- ialloc_set_space(idmemory, r_space(op));
- pfont = gs_font_alloc(imemory, pstype, &gs_font_procs_default, NULL,
- "buildfont(font)");
- pdata = ialloc_struct(font_data, &st_font_data,
- "buildfont(data)");
- if (pfont == 0 || pdata == 0)
- code = gs_note_error(e_VMerror);
- else if (fid_op)
- code = add_FID(i_ctx_p, fid_op, pfont, iimemory);
- if (code < 0) {
- ifree_object(pdata, "buildfont(data)");
- ifree_object(pfont, "buildfont(font)");
- ialloc_set_space(idmemory, space);
- return code;
- }
- refset_null((ref *) pdata, sizeof(font_data) / sizeof(ref));
- ref_assign_new(&pdata->dict, op);
- ref_assign_new(&pdata->BuildChar, &pbuild->BuildChar);
- ref_assign_new(&pdata->BuildGlyph, &pbuild->BuildGlyph);
- if (pencoding)
- ref_assign_new(&pdata->Encoding, pencoding);
- pfont->client_data = pdata;
- pfont->FontType = ftype;
- pfont->FontMatrix = mat;
- pfont->BitmapWidths = false;
- pfont->ExactSize = fbit_use_bitmaps;
- pfont->InBetweenSize = fbit_use_outlines;
- pfont->TransformedChar = fbit_use_outlines;
- pfont->WMode = 0;
- pfont->procs.encode_char = zfont_encode_char;
- pfont->procs.callbacks.glyph_name = zfont_glyph_name;
- pfont->procs.callbacks.known_encode = zfont_known_encode;
- ialloc_set_space(idmemory, space);
- copy_font_name(&pfont->font_name, &fname);
- *ppfont = pfont;
- return 0;
- }
-
- /* Get the string corresponding to a font name. */
- /* If the font name isn't a name or a string, return an empty string. */
- private void
- get_font_name(ref * pfname, const ref * op)
- {
- switch (r_type(op)) {
- case t_string:
- *pfname = *op;
- break;
- case t_name:
- name_string_ref(op, pfname);
- break;
- default:
- /* This is weird, but legal.... */
- make_empty_string(pfname, a_readonly);
- }
- }
-
- /* Copy a font name into the gs_font structure. */
- private void
- copy_font_name(gs_font_name * pfstr, const ref * pfname)
- {
- uint size = r_size(pfname);
-
- if (size > gs_font_name_max)
- size = gs_font_name_max;
- memcpy(&pfstr->chars[0], pfname->value.const_bytes, size);
- /* Following is only for debugging printout. */
- pfstr->chars[size] = 0;
- pfstr->size = size;
- }
-
- /* Finish building a font, by calling gs_definefont if needed. */
- int
- define_gs_font(gs_font * pfont)
- {
- return (pfont->base == pfont && pfont->dir == 0 ?
- /* i.e., unregistered original font */
- gs_definefont(ifont_dir, pfont) :
- 0);
- }
-